From 8ab01c502c557587d5fbf8f3db6b5c47fc288710 Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Wed, 27 Jul 2005 16:18:02 +0000 Subject: [PATCH] Add IBM Cyclone support to Xen. Signed-off-by: Keir Fraser --- xen/arch/x86/time.c | 96 +++++++++++++++++-- xen/include/asm-x86/fixmap.h | 1 + .../asm-x86/mach-summit/mach_mpparse.h | 4 +- 3 files changed, 93 insertions(+), 8 deletions(-) diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index e9eda9f99b..2412f1a30e 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -199,13 +199,13 @@ void calibrate_tsc_bp(void) outb(CALIBRATE_LATCH >> 8, PIT_CH2); tsc_calibrate_status = 1; - wmb(); + wmb(); while ( (inb(0x61) & 0x20) == 0 ) continue; tsc_calibrate_status = 2; - wmb(); + wmb(); while ( atomic_read(&tsc_calibrate_gang) != 0 ) mb(); @@ -233,7 +233,6 @@ void calibrate_tsc_ap(void) atomic_dec(&tsc_calibrate_gang); } - /************************************************************ * PLATFORM TIMER 1: PROGRAMMABLE INTERVAL TIMER (LEGACY PIT) */ @@ -280,6 +279,8 @@ static int init_pit(void) platform_timer_stamp = pit_counter64; set_time_scale(&platform_timer_scale, CLOCK_TICK_RATE); + printk("Platform timer is PIT\n"); + return 1; } @@ -318,12 +319,12 @@ static int init_hpet(void) if ( (hpet_address == 0) && opt_hpet_force ) { - printk(KERN_WARNING "WARNING: Enabling HPET base manually!\n"); + printk(KERN_WARNING "WARNING: Enabling HPET base manually!\n"); outl(0x800038a0, 0xcf8); outl(0xff000001, 0xcfc); outl(0x800038a0, 0xcf8); hpet_address = inl(0xcfc) & 0xfffffffe; - printk(KERN_WARNING "WARNING: Enabled HPET at %#lx.\n", hpet_address); + printk(KERN_WARNING "WARNING: Enabled HPET at %#lx.\n", hpet_address); } if ( hpet_address == 0 ) @@ -383,6 +384,89 @@ static int init_hpet(void) hpet_overflow(NULL); platform_timer_stamp = hpet_counter64; + printk("Platform timer is HPET\n"); + + return 1; +} + +/************************************************************ + * PLATFORM TIMER 3: IBM 'CYCLONE' TIMER + */ + +int use_cyclone; + +/* + * Although the counter is read via a 64-bit register, I believe it is actually + * a 40-bit counter. Since this will wrap, I read only the low 32 bits and + * periodically fold into a 64-bit software counter, just as for PIT and HPET. + */ +#define CYCLONE_CBAR_ADDR 0xFEB00CD0 +#define CYCLONE_PMCC_OFFSET 0x51A0 +#define CYCLONE_MPMC_OFFSET 0x51D0 +#define CYCLONE_MPCS_OFFSET 0x51A8 +#define CYCLONE_TIMER_FREQ 100000000 + +/* Protected by platform_timer_lock. */ +static u64 cyclone_counter64; +static u32 cyclone_stamp; +static struct ac_timer cyclone_overflow_timer; +static volatile u32 *cyclone_timer; /* Cyclone MPMC0 register */ + +static void cyclone_overflow(void *unused) +{ + u32 counter; + + spin_lock(&platform_timer_lock); + counter = *cyclone_timer; + cyclone_counter64 += (u32)(counter - cyclone_stamp); + cyclone_stamp = counter; + spin_unlock(&platform_timer_lock); + + set_ac_timer(&cyclone_overflow_timer, NOW() + MILLISECS(20000)); +} + +static u64 read_cyclone_count(void) +{ + return cyclone_counter64 + (u32)(*cyclone_timer - cyclone_stamp); +} + +static volatile u32 *map_cyclone_reg(unsigned long regaddr) +{ + unsigned long pageaddr = regaddr & PAGE_MASK; + unsigned long offset = regaddr & ~PAGE_MASK; + set_fixmap_nocache(FIX_CYCLONE_TIMER, pageaddr); + return (volatile u32 *)(fix_to_virt(FIX_CYCLONE_TIMER) + offset); +} + +static int init_cyclone(void) +{ + u32 base; + + if ( !use_cyclone ) + return 0; + + /* Find base address. */ + base = *(map_cyclone_reg(CYCLONE_CBAR_ADDR)); + if ( base == 0 ) + { + printk(KERN_ERR "Cyclone: Could not find valid CBAR value.\n"); + return 0; + } + + /* Enable timer and map the counter register. */ + *(map_cyclone_reg(base + CYCLONE_PMCC_OFFSET)) = 1; + *(map_cyclone_reg(base + CYCLONE_MPCS_OFFSET)) = 1; + cyclone_timer = map_cyclone_reg(base + CYCLONE_MPMC_OFFSET); + + read_platform_count = read_cyclone_count; + + init_ac_timer(&cyclone_overflow_timer, cyclone_overflow, NULL, 0); + cyclone_overflow(NULL); + platform_timer_stamp = cyclone_counter64; + set_time_scale(&platform_timer_scale, CYCLONE_TIMER_FREQ); + + printk("Platform timer is IBM Cyclone\n"); + return 1; } @@ -427,7 +511,7 @@ static void platform_time_calibration(void) static void init_platform_timer(void) { - if ( !init_hpet() ) + if ( !init_cyclone() && !init_hpet() ) BUG_ON(!init_pit()); } diff --git a/xen/include/asm-x86/fixmap.h b/xen/include/asm-x86/fixmap.h index 586128baf8..8b08cdcd80 100644 --- a/xen/include/asm-x86/fixmap.h +++ b/xen/include/asm-x86/fixmap.h @@ -31,6 +31,7 @@ enum fixed_addresses { FIX_ACPI_BEGIN, FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1, FIX_HPET_BASE, + FIX_CYCLONE_TIMER, __end_of_fixed_addresses }; diff --git a/xen/include/asm-x86/mach-summit/mach_mpparse.h b/xen/include/asm-x86/mach-summit/mach_mpparse.h index 88f6c50da2..75b06db77f 100644 --- a/xen/include/asm-x86/mach-summit/mach_mpparse.h +++ b/xen/include/asm-x86/mach-summit/mach_mpparse.h @@ -30,7 +30,7 @@ static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, (!strncmp(productid, "VIGIL SMP", 9) || !strncmp(productid, "EXA", 3) || !strncmp(productid, "RUTHLESS SMP", 12))){ - /*use_cyclone = 1;*/ /*enable cyclone-timer*/ + use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); /*usb_early_handoff = 1;*/ return 1; @@ -44,7 +44,7 @@ static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id) if (!strncmp(oem_id, "IBM", 3) && (!strncmp(oem_table_id, "SERVIGIL", 8) || !strncmp(oem_table_id, "EXA", 3))){ - /*use_cyclone = 1;*/ /*enable cyclone-timer*/ + use_cyclone = 1; /*enable cyclone-timer*/ setup_summit(); /*usb_early_handoff = 1;*/ return 1; -- 2.30.2